
// extensions namespace
E = new Object();

/**
 * Accessor for a DHTML object extension wrapper.
 * 
 * @param {object}
 *          e The object (element, element ID, document or window) to wrap.
 * @param {document}
 *          [doc] optional document to capture the element for the given ID
 * @return {E.Dom, E.Doc, E.Wnd} The wrapper object depending on the parameter
 *         object.
 */
E.wrap = function(e, doc) {
	if (!e)
		return null;
	if (typeof(e) == "string") {
		e = ((doc)?doc:document).getElementById(e);
		if (!e)
			return null;
	}
	if (e._e)
		return e._e;
	var _e;
	if (e.ownerDocument)
		_e = new E.Dom(e);
	else if (e.documentElement)
		_e = new E.Doc(e);
	else if (e.document && e.top)
		_e = new E.Wnd(e);
	if (_e) {
		try {
			e._e = _e;
		}
		catch (ex) {
			// XML DOM nodes in IE are implemented in an object, external to the
			// browser (MSXML).
			// They don't support setting additional members like the other JavaScript
			// objects.
			//
			// Be careful not to compare the wrappers directly, since there could be
			// multiple wrappers for one XML DOM node.
		}
		return _e;
	}
	return null;
}

/**
 * Accessor for a DOM node wrapper.
 * 
 * @param {object}
 *          e The object (element, element ID, document or window) to wrap. For
 *          a document the documentElement is wrapped, for a window, it's
 *          document's documentElement.
 * @return {E.Dom} The DOM node wrapper object.
 */
function Dom(e, doc) {
	if (!e)
		return null;
	if (typeof(e) == "string")
		e = ((doc)?doc:document).getElementById(e);
	else if (e.element)
		return e;
	else if (e.documentElement)
		// document
		e = e.documentElement;
	else if (e.doc && e.doc.documentElement)
		// E.Doc
		e = e.doc.documentElement;
	else if (e.document && e.top)
		e = e.document.documentElement;
	else if (e.wnd && e.wnd.document && e.wnd.top)
		// E.Wnd
		e = e.wnd.document.documentElement;
	return E.wrap(e);
}

/**
 * Accessor for a document wrapper.
 * 
 * @param {object}
 *          e The object (element, document or window) to wrap. For an DOM
 *          element the owner Document is wrapped, for a window, it's document.
 * @return {E.Doc} The document wrapper object.
 */
function Doc(e) {
	if (!e)
		return E.wrap(document);
	if (e.doc)
		return e;
	if (e.ownerDocument)
		// element
		e = e.ownerDocument;
	else if (e.element && e.element.ownerDocument)
		// E.Dom
		e = e.element.ownerDocument;
	else if (e.document && e.top)
		// window
		e = e.document;
	else if (e.wnd && e.wnd.document && e.wnd.top)
		// E.Wnd
		e = e.wnd.document;
	return E.wrap(e);
}

/**
 * Accessor for a window wrapper.
 * 
 * @param {object}
 *          e The object (element, document or window) to wrap. For an DOM
 *          element the ownerDocument's window is wrapped, for a document, it's
 *          window.
 * @return {E.Wnd} The window wrapper object.
 */
function Wnd(e) {
	if (!e)
		return E.wrap(window);
	if (e.wnd)
		return e;
	if (!e.setTimeout) {
		var doc = e;
		if (e.ownerDocument)
			doc = e.ownerDocument;
		else if (e.element && e.element.ownerDocument)
			doc = e.element.ownerDocument;
		else if (e.doc && e.doc.documentElement)
			doc = e.doc;
		if (doc.parentWindow)
			e = doc.parentWindow;
		else if (doc.defaultView)
			e = doc.defaultView;
		else if (doc.contentWindow)
			e = doc.contentWindow;
	}
	return E.wrap(e);
}

E.Base = function() {
	this.evnTypes = new Object();
}

E.Base.prototype.addEventListener = function(type, fnHandler, callContext) {
	var listeners = this.evnTypes[type];
	if (!listeners)
		this.evnTypes[type] = listeners = new Array();
	if (callContext)
		fnHandler.callContext = callContext;
	listeners.push(fnHandler);
}

E.Base.prototype.removeEventListener = function(type, fnHandler) {
	var listeners = this.evnTypes[type];
	if (!listeners)
		return;
	var nL = new Array();
	for (var i = 0; i < listeners.length; ++i) {
		var h = listeners[i];
		if (h != fnHandler)
			nL.push(h);
	}
	this.evnTypes[type] = nL;
}

E.Base.prototype.dispatchEvent = function(evn) {
	var listeners = this.evnTypes[evn.type];
	if (!listeners)
		return;
	for (var i = 0; i < listeners.length; ++i) {
		var fn = listeners[i];
		var callCtx = this;
		if (fn.callContext)
			callCtx = fn.callContext;
		fn.call(callCtx, evn);
	}
}

/**
 * @class document wrapper class.
 * @param {document}
 *          doc The document to wrap.
 * @constructor
 */
E.Doc = function(doc) {
	E.Doc._super.call(this);
	if (!doc)
		this.doc = document;
	else
		this.doc = doc;
	this.head = this.doc.getElementsByTagName("head")[0];
	this.body = this.doc.getElementsByTagName("body")[0];
}
Object.extend("E.Doc", "E.Base");

E.Doc.prototype.getMeta = function(name) {
	var metas = this.head.getElementsByTagName("meta");
	for (var i = 0; i < metas.length; ++i) {
		var meta = metas[i];
		if (meta.name == name)
			return meta;
	}
	return null;
}

// css
E.Doc.prototype.addCss = function(url) {
	var css = this.doc.createElement("link");
	css.setAttribute("type", "text/css");
	css.setAttribute("href", url);
	css.setAttribute("rel", "stylesheet");
	this.head.appendChild(css);
}

E.Doc.prototype.getViewUri = function() {
	var href = this.doc.location.href.substring(BasePath.get().length);
	var fPos = href.indexOf("#");
	if (0 < fPos)
		return href.substring(0, fPos);
	return href;
}

// cross browser document.importNode(node, true).
// copy from sarissa 0.9.8.1 (some changes...)
// see http://dev.abiss.gr/sarissa
E.Doc.prototype.importNode = function(node, deep) {
	if (typeof this.doc.importNode != "function") {
		try {
			/**
			 * Implementation of importNode for the context window document in IE. If
			 * <code>oNode</code> is a TextNode, <code>bChildren</code> is
			 * ignored.
			 * 
			 * @param oNode
			 *          the Node to import
			 * @param bChildren
			 *          whether to include the children of oNode
			 * @returns the imported node for further use
			 */
			this.doc.importNode = function(oNode, bChildren) {
				var tmp;
				if (oNode.nodeName == '#text') {
					return this.createTextNode(oNode.data);
				}
				else {
					if (oNode.nodeName == "tbody" || oNode.nodeName == "tr") {
						tmp = this.createElement("table");
					}
					else if (oNode.nodeName == "td") {
						tmp = this.createElement("tr");
					}
					else if (oNode.nodeName == "option") {
						tmp = this.createElement("select");
					}
					else {
						tmp = this.createElement("div");
					};
					if (bChildren) {
						tmp.innerHTML = oNode.xml?oNode.xml:oNode.outerHTML;
					}
					else {
						tmp.innerHTML = oNode.xml?oNode.cloneNode(false).xml:oNode.cloneNode(false).outerHTML;
					};
					return tmp.getElementsByTagName("*")[0];
				}
			};
		}
		catch (e) {
		};
	}
	return this.doc.importNode(node, deep);
}

E.Doc.prototype.addEventListener = function(type, fnHandler, callContext) {
	E.Doc._super.prototype.addEventListener.call(this, type, fnHandler, callContext);
	return new EventListener(this.doc, type, fnHandler, (callContext)?callContext:this);
}

E.Doc.prototype.removeEventListener = function(type, fnHandler) {
	EventListener.removeListener(this.doc, type, fnHandler);
	E.Doc._super.prototype.removeEventListener.call(this, type, fnHandler);
}

// A general DOM element
E.Dom = function(element) {
	E.Dom._super.call(this);
	this.element = element;
}
Object.extend("E.Dom", "E.Base");

// Merge a DOM node into a target DOM.
// Only differences will be written into the target DOM.
E.Dom.prototype.mergeInto = function(targetDom) {
	// simply replace all the HTML
	targetDom.innerHTML = this.serializeContent();
	return;
	// the node-by-node merge should work better, since it would leave
	// the state of the unmodified part of the target DOM...
	// debug("&#160;merge " +dom.nodeName);
	var i;
	// copy or create new attributes
	var attrs = this.element.attributes;
	for (i = 0; i < attrs.length; ++i) {
		var a = attrs[i];
		var ta = targetDom.getAttributeNode(a.name);
		if (!ta || (ta.value != a.value)) {
			// debug("set " +a.name +"="+a.value);
			// if (ta && ta.value)
			// debug("(" +ta.value+")");
			if ("class" == a.name)
				targetDom.className = a.nodeValue;
			else if ("style" == a.name)
				targetDom.style.cssText = a.nodeValue;
			else
				targetDom.setAttribute(a.name, a.value);
			if ("checked" == a.name)
				targetDom.defaultChecked = true;
		}
	}
	// remove deleted attributes
	var targetAttrs = targetDom.attributes;
	for (i = 0; i < targetAttrs.length; ++i) {
		var ta = targetAttrs[i];
		if (!ta.specified)
			continue;
		var a = this.element.getAttributeNode(ta.name);
		if (!a) {
			targetDom.removeAttribute(ta.name);
			// debug("delete " +ta.name);
		}
	}
	// copy or create new child nodes
	var targetDoc = targetDom.ownerDocument;
	var childNodes = this.element.childNodes;
	var targetChildNodes = targetDom.childNodes;
	for (i = 0; i < childNodes.length; ++i) {
		var n = childNodes[i];
		// debug("n["+i+"] " +n.nodeName);
		if (i >= targetChildNodes.length) {
			targetDom.appendChild(Doc(targetDoc).importNode(n, true));
			// debug("create " +n.nodeName);
			continue;
		}
		var t = targetChildNodes[i];
		if (n.nodeType == 1) {
			// Node.ELEMENT_NODE
			if (n.nodeName.toLowerCase() == t.nodeName.toLowerCase()) {
				var d = new Dom(n);
				d.mergeInto(t);
			}
			else {
				targetDom.replaceChild(Doc(targetDoc).importNode(n, true), t);
				// debug("replace "+t.nodeName+" with " +n.nodeName+"
				// ("+t.id+":"+n.id+")");
			}
		}
		else if (n.nodeType == 3) {
			// Node.TEXT_NODE
			if (t.nodeType != 3) {
				targetDom.replaceChild(targetDoc.createTextNode(n.nodeValue), t);
				// debug("replace "+t.nodeName+" with '" +n.nodeValue+"'");
				// IE likes this...
				targetDom.innerHTML = targetDom.innerHTML;
			}
			else if (n.nodeValue != t.nodeValue) {
				// debug("text '" +t.nodeValue+"' '"+n.nodeValue+"'");
				t.nodeValue = n.nodeValue;
				// IE likes this...
				targetDom.innerHTML = targetDom.innerHTML;
			}
		}
		else {
			targetDom.replaceChild(Doc(targetDoc).importNode(n, true), t);
			// debug("replace2 "+t.nodeName+" with " +n.nodeName);
			targetDom.innerHTML = targetDom.innerHTML;
		}
	}
	// remove deleted child nodes
	for (i = targetChildNodes.length - 1; i >= childNodes.length; --i) {
		// debug("del "+targetChildNodes[i].nodeName);
		targetDom.removeChild(targetChildNodes[i]);
	}
		// debug("&#160;...done " +dom.nodeName);
}

// Clean up empty text nodes.
E.Dom.prototype.cleanup = function() {
	var cleanupNode = function(node) {
		var childNodes = node.childNodes;
		for (var i = childNodes.length - 1; i >= 0; --i) {
			var n = childNodes[i];
			if (n.nodeType == 1)
				cleanupNode(n);
			else if ((n.nodeType == 3) && !n.nodeValue.match("[^ \f\n\r\t]") && (n.nodeValue != " "))
				node.removeChild(n);
		}
	}
	cleanupNode(this.element);
	this.element.normalize();
}

// Serialize XHTML DOM content.
E.Dom.prototype.serializeContent = function() {
	var serializeNode = function(n) {
		if (n.nodeType == 1) {
			var text = "";
			var prefixPos = n.nodeName.indexOf(":");
			var tagName = n.nodeName.toLowerCase();
			if (0 <= prefixPos)
				tagName = tagName.substring(prefixPos + 1);
		  text += "<" + tagName;
			var attrs = n.attributes;
			for (var j = 0; j < attrs.length; ++j) {
				var a = attrs[j];
				if (!a.specified)
					continue;
				if (a.nodeName == "xmlns")
					// for HTML DOMs we don't need the namespace declaration for every
					// node...
					continue;
				text += " " + a.name + "=\"" + a.value.escapeText() + "\"";
			}
			if (1 > n.childNodes.length) {
				// a simple empty element closing does not work for <a name="..."/> . We
				// need to
				// have <a name="..."></a> for some reason.
				text += "></" + tagName + ">";
			}
			else {
				text += ">";
				var childNodes = n.childNodes;
				for (var i = 0; i < childNodes.length; ++i)
					text += serializeNode(childNodes[i]);
				text += "</" + tagName + ">";
			}
			return text;
		}
		else if (n.nodeType == 2) { // attribute nodes
			return " " + n.name + "=\"" + n.value.escapeText() + "\"";
		}
		else if (n.nodeType == 3) { // text nodes
			return n.nodeValue.escapeText();
		}
		else if (n.nodeType == 4) { // cdata nodes
			return n.nodeValue.escapeText();
		}
		else if (n.nodeType == 9) { // document nodes
			return serializeNode(n.documentElement);
		}
		else {
			//alert("No support to serialize node type " + n.nodeType + "!");
			//return n.innerHTML.replace(/&nbsp;/ig, "&#160;");
			// just ignore the rest (comment, entity, document-type, notation,... nodes)
			return "";
		}
	}

	var text = "";
	var childNodes = this.element.childNodes;
	for (var i = 0; i < childNodes.length; ++i)
		text += serializeNode(childNodes[i]);
	return text;
}

String.prototype.escapeText = function() {
	return this.replace("&", "&amp;", "g").replace("<", "&lt;", "g").replace(">", "&gt;", "g");
}

E.Dom.prototype.getChild = function(nodeName) {
	var childNodes = this.element.childNodes;
	for (var i = 0; i < childNodes.length; ++i) {
		var e = childNodes[i];
		if (e.nodeName == nodeName)
			return e;
	}
	return null;
}

E.Dom.prototype.getTextContent = function() {
	return (this.element.textContent)?this.element.textContent:this.element.text;
}

E.Dom.prototype.createChild = function(tagName, innerHtml) {
	var e = this.element.ownerDocument.createElement(tagName);
	if (innerHtml)
		e.innerHTML = innerHtml;
	this.element.appendChild(e);
	return e;
}

E.Dom.prototype.cloneNode = function(deep) {
	if (navigator.userAgent.indexOf("MSIE") > 0) {
		var tmp = this.element.ownerDocument.createElement("div");
		tmp.innerHTML = this.element.outerHTML;
		var clone = tmp.firstChild;
		tmp.removeNode(clone);
		if (!deep)
			clone.innerHTML = "";
		return clone;
	}
	else {
		return this.element.cloneNode(deep);
	}
}

E.Dom.prototype.isVisible = function() {
	return (this.element.style.display != "none") && (this.element.style.visibility != "hidden");
}

E.Dom.prototype.display = function(show, displayStyle) {
	if (show) {
		if (!this._originalDisplayStyle)
			this._originalDisplayStyle = this.element.style.display;
		if (displayStyle)
			this.element.style.display = displayStyle;
		else if (!this._originalDisplayStyle || (this._originalDisplayStyle == "none"))
			this.element.style.display = "";
		else
			this.element.style.display = this._originalDisplayStyle;
	}
	else {
		this.element.style.display = "none";
	}
}

E.Dom.prototype.show = function(displayStyle) {
	this.display(true, displayStyle);
}

E.Dom.prototype.hide = function() {
	this.display(false);
}

E.Dom.prototype.toggle = function(displayStyle) {
	this.display(this.element.style.display == "none", displayStyle);
}

E.Dom.prototype.isTextEdit = function() {
	var e = this.element;
	while (e != null) {
		if ((this.element.localName == "input") || (this.element.localName == "textarea")
				|| (this.element.localName == "INPUT") || (this.element.localName == "TEXTAREA")
				|| (this.element.contentEditable == "true") || (this.element.contentEditable == true))
			return true;
		e = e.parentNode;
	}
	return false;
}

E.Dom.prototype.getChildrenByClassName = function(className) {
	var results = new Array();
	var nodes = this.element.childNodes;
	for (var i = 0; i < nodes.length; ++i) {
		var n = nodes[i];
		if ((typeof(n.className) == "string") && (n.className.indexOf(className) >= 0))
			results.push(n);
	}
	return results;
}

E.Dom.prototype.getFirstChildByClassName = function(className) {
	var n = this.element.firstChild;
	while (n && ((typeof(n.className) != "string") || (n.className.indexOf(className) < 0)))
	  n = n.nextSibling;
	return n;
}

E.Dom.prototype.getElementsByClassName = function(className) {
	var results = new Array();
	var elements = this.element.getElementsByTagName("*");
	for (var i = 0; i < elements.length; ++i) {
		var e = elements[i];
		if ((typeof(e.className) == "string") && (e.className.indexOf(className) >= 0))
			results.push(e);
	}
	return results;
}

E.Dom.prototype.getElementsByVector = function(vector) {
	var results = new Array();
	var elements = this.element.getElementsByTagName("*");
	var sV = this.getScrollVector();
	vector = [vector[0] + sV[0], vector[1] + sV[1]];
	for (var i = 0; i < elements.length; ++i) {
		var e = new E.Dom(elements[i]);
		var v = e.getVector();
		v = [vector[0] - v[0], vector[1] - v[1]];
		if ((v[0] >= 0) && (v[0] <= e.element.offsetWidth) && (v[1] >= 0)
				&& (v[1] <= e.element.offsetHeight))
			results.push(e.element);
	}
	return results.reverse();
}

E.Dom.prototype.getNextSiblingElement = function() {
	var node = this.element;
	while (node = node.nextSibling) {
		if (1 == node.nodeType)
			return node;
	}
	return null;
}

// set opacity of a HTML DOM element
// @param dom HTML DOM element to set the opacity for.
// @param value Opacity value (0.0: transparent, 1.0: fully shown)
E.Dom.prototype.setOpacity = function(value) {
	this.element.style.filter = "alpha(opacity=" + value * 100 + ")";
	this.element.style.opacity = value;
	this.element.style.MozOpacity = value;
}

E.Dom.prototype.getSize = function() {
	return [this.element.offsetWidth, this.element.offsetHeight];
}

E.Dom.prototype.setSize = function(size) {
	this.element.style.width = size[0] + "px";
	this.element.style.heigth = size[1] + "px";
}

// calculates the top, left position of the this element
// relativ to the documents top, left most position.
E.Dom.prototype.getVector = function() {
	var element = this.element;
	var absOffsetTop = 0;
	var absOffsetLeft = 0;
	while ((null != element) && (1 == element.nodeType)) {
		absOffsetTop += element.offsetTop;
		absOffsetLeft += element.offsetLeft;
		element = element.offsetParent;
	}
	return [absOffsetLeft, absOffsetTop];
}

// calculates the top, left scroll position of the given element
// relativ to the documents top, left most position.
E.Dom.prototype.getScrollVector = function() {
	var element = this.element;
	var absOffsetTop = 0;
	var absOffsetLeft = 0;
	while ((null != element) && (1 == element.nodeType)) {
		absOffsetTop += element.scrollTop;
		absOffsetLeft += element.scrollLeft;
		element = element.parentNode;
	}
	return [absOffsetLeft, absOffsetTop];
}

E.Dom.prototype.getScrollbarTotalSize = function() {
	if (!E.Dom.systemScrollbarSize) {
		// default scrollbar width of 16px
		var tmp = this.element.ownerDocument.createElement("div");
		tmp.style.width = "100px";
		tmp.style.height = "100px";
		tmp.style.fontSize = "100px";
		tmp.style.overflow = "scroll";
		tmp.innerHTML = "dummy<br/>dummy";
		this.element.appendChild(tmp);
		E.Dom.systemScrollbarSize = [100 - tmp.clientWidth, 100 - tmp.clientHeight];
		// alert(E.Dom.systemScrollbarSize+" | "+[tmp.offsetWidth,
		// tmp.offsetHeight]);
		this.element.removeChild(tmp);
	}
	var sb = E.Dom.systemScrollbarSize;
	var s = [0, 0];
	var e = this.element;
	while (null != e) {
		if (e.scrollWidth > e.clientWidth)
			s[0] += sb[0];
		if (e.scrollHeight > e.clientHeight)
			s[1] += sb[1];
		e = e.parentNode;
	}
	return s;
}

E.Dom.prototype.moveTo = function(v, anchor) {
	if (anchor == 1) { // top - right
		this.element.style.right = v[0] + "px";
		this.element.style.top = v[1] + "px";
	}
	else if (anchor == 2) { // bottom - right
		this.element.style.right = v[0] + "px";
		this.element.style.bottom = v[1] + "px";
	}
	else if (anchor == 3) { // bottom - left
		this.element.style.left = v[0] + "px";
		this.element.style.bottom = v[1] + "px";
	}
	else if (this.element.moveTo) { // top - left (default)
		this.element.moveTo(v[0], v[1]);
	}
	else { // top - left
		this.element.style.left = v[0] + "px";
		this.element.style.top = v[1] + "px";
	}
}

// looks for an ancestor of an element.
E.Dom.prototype.hasAncestor = function(ancestor) {
	var element = this.element;
	while (element && (element != document.body)) {
		if (element == ancestor)
			return true;
		element = element.parentNode;
	}
	return false;
}

E.Dom.prototype.isAncestorOf = function(node) {
	while (node && (node != document.body)) {
		if (node == this.element)
			return true;
		node = node.parentNode;
	}
	return false;
}

E.Dom.prototype.addStyleClass = function(className) {
	if (this.element.className.indexOf(className) < 0)
		this.element.className += " " + className;
}

E.Dom.prototype.removeStyleClass = function(className) {
	this.element.className = this.element.className.replace(className, "");
}

// checks for an ancestor with a certain class name.
E.Dom.prototype.hasAncestorWithClass = function(className) {
	var node = this.element;
	while (node && (node != document.body)) {
		if (node.className == className)
			return true;
		node = node.parentNode;
	}
	return false;
}

E.Dom.prototype.addEventListener = function(type, fnHandler, callContext) {
	E.Dom._super.prototype.addEventListener.call(this, type, fnHandler, callContext);
	return new EventListener(this.element, type, fnHandler, (callContext)?callContext:this);
}

E.Dom.prototype.removeEventListener = function(type, fnHandler) {
	EventListener.removeListener(this.element, type, fnHandler);
	E.Dom._super.prototype.removeEventListener.call(this, type, fnHandler);
}

// window extensions
E.Wnd = function(wnd) {
	E.Wnd._super.call(this);
	this.wnd = wnd;
}
Object.extend("E.Wnd", "E.Base");

E.Wnd.prototype.open = function(url, id, features) {
	if (!this._wnds)
		this._wnds = {};
	if (this._wnds[id] && !this._wnds[id].closed)
		this._wnds[id].focus();
	else
		this._wnds[id] = this.wnd.open(url, id, features);
	return this._wnds[id];
}

E.Wnd.prototype.getInnerSize = function() {
	if (typeof(this.wnd.innerWidth) == 'number')
		// Non-IE
		return [this.wnd.innerWidth, this.wnd.innerHeight];
	var doc = this.wnd.document;
	if (doc.documentElement && (typeof(doc.documentElement.clientWidth) == 'number'))
		// IE 6+ in 'standards compliant mode'
		return [doc.documentElement.clientWidth, doc.documentElement.clientHeight];
	// IE 4 compatible
	return [doc.body.clientWidth, doc.body.clientHeight];
}

E.Wnd.prototype.addEventListener = function(type, fnHandler, callContext) {
	E.Wnd._super.prototype.addEventListener.call(this, type, fnHandler, callContext);
	return new EventListener(this.wnd, type, fnHandler, (callContext)?callContext:this);
}

E.Wnd.prototype.removeEventListener = function(type, fnHandler) {
	EventListener.removeListener(this.wnd, type, fnHandler);
	E.Wnd._super.prototype.removeEventListener.call(this, type, fnHandler);
}

// Configuration container
E.Config = new Object();

E.Config.get = function(context) {
	var c = E.Config[context];
	if (!c)
		E.Config[context] = c = new Object();
	return c;
}

E.Config.apply = function(obj, context) {
	var c = E.Config[context];
	if (!c)
		return;
	for (var m in c)
		obj[m] = c[m];
}
